home *** CD-ROM | disk | FTP | other *** search
/ Cream of the Crop 1 / Cream of the Crop 1.iso / PROGRAM / CBASE102.ARJ / MANX.C < prev    next >
Text File  |  1991-08-22  |  12KB  |  429 lines

  1. /*    Copyright (c) 1989 Citadel    */
  2. /*       All Rights Reserved        */
  3.  
  4. /* #ident    "@(#)manx.c    1.4 - 91/08/22" */
  5.  
  6. #include <ansi.h>
  7.  
  8. /* ansi headers */
  9. #include <errno.h>
  10. #include <limits.h>
  11. #include <stdio.h>
  12. #ifdef AC_STDLIB
  13. #include <stdlib.h>
  14. #endif
  15. #ifdef AC_STRING
  16. #include <string.h>
  17. #endif
  18.  
  19. /* function declarations */
  20. #ifdef AC_PROTO
  21. static int manputs(const char *cs, FILE *fp, long *pagep, long *linep);
  22. #else
  23. static int manputs();
  24. #endif
  25.  
  26. /* constants */
  27. #define PAGELEN        (60)        /* default page length */
  28. #define BACKSLASH    ('\\')        /* char to begin escape sequence */
  29. #define PAGINATOR    "\f"        /* string to use as page separator */
  30. #define LINELEN_MAX    (256)        /* maximum line length */
  31. #define PROGNAME    "manx"        /* default program name */
  32. #define USAGE        "usage: %s [language] [page-length]\n"
  33.                     /* usage message */
  34.  
  35. typedef struct {        /* language definition structure */
  36.     char option[11];    /* language command line option */
  37.     char begin[21];        /* marker for beginning of manual entry */
  38.     char end[21];        /* marker for end of manual entry */
  39.     char comment[11];    /* character sequence that begins comment */
  40.     int  flags;        /* flags */
  41. } lang_t;
  42.  
  43. /* lang_t bit flags */
  44. #define LINECMT        (1)
  45. #define BLOCKCMT    (2)
  46.  
  47. /* language definitions */
  48. lang_t langs[] = {
  49.     {"a",  "--man", "--end", "--", LINECMT},    /* Ada */
  50.     {"as", ";man",  ";end",  ";",  LINECMT},    /* ASM */
  51.     {"c",  "/*man", "*/",    "/*", BLOCKCMT},    /* C */
  52.     {"f",  "Cman", "Cend",   "C",  LINECMT},    /* Fortran */
  53.     {"l",  ";man", ";end",   ";",  LINECMT},    /* Lisp */
  54.     {"m",  "(*man", "*)",    "(*", BLOCKCMT},    /* Modula-2 */
  55.     {"p",  "{man",  "}",     "{",  BLOCKCMT},    /* Pascal */
  56.     {"pl", "\"man", "\"",    "\"", BLOCKCMT},    /* Prolog */
  57.     {"st", "\"man", "\"",    "\"", BLOCKCMT},    /* Smalltalk */
  58. };
  59.  
  60. /* index into langs array for each language */
  61. #define ADA        (1)
  62. #define ASM        (2)
  63. #define C        (3)
  64. #define FORTRAN        (4)
  65. #define LISP        (5)
  66. #define MODULA_2    (6)
  67. #define PASCAL        (7)
  68. #define PROLOG        (8)
  69. #define SMALLTALK    (9)
  70.  
  71. #define LANG        C        /* default language */
  72.  
  73. /*man---------------------------------------------------------------------------
  74. NAME
  75.      manx - manual entry extracter
  76.  
  77. SYNOPSIS
  78.      manx [language] [page-length]
  79.  
  80. DESCRIPTION
  81.      The manx command extracts manual entries from source files.  The
  82.      source files are read from stdin and the manual entries are
  83.      written to stdout.  Each individual manual entry is separated
  84.      into pages by form feeds and terminated with a form feed.
  85.  
  86.      The language option specifies the language of the source file.
  87.      The languages supported are:
  88.  
  89.                            Ada           -a
  90.                            assembly      -as
  91.                            C             -c
  92.                            Fortran       -f
  93.                            Lisp          -l
  94.                            Modula-2      -m
  95.                            Pascal        -p
  96.                            Prolog        -pl
  97.                            Smalltalk     -st
  98.  
  99.      The default language is C.
  100.  
  101.      The page-length argument can be used to set the page length.
  102.      Pagination may be disabled by specifying a page length of 0.
  103.      The default page length is 60.
  104.  
  105.      The beginning of a manual entry is marked by the character
  106.      sequence (language dependent) to start a comment immediately
  107.      followed by the characters 'man'.  This marker must appear in the
  108.      leftmost column allowed by the language.  For block comments, the
  109.      end of the manual entry is marked by the end of the comment.  For
  110.      line comments, the end of a manual entry is marked by the
  111.      character sequence to end a comment immediately followed by the
  112.      characters 'end'.  All lines between but not including these
  113.      constitute the manual entry.
  114.  
  115.      The following escape sequences can be used within a manual entry:
  116.  
  117.                   audible alert       BEL       \\a
  118.                   backspace           BS        \\b
  119.                   form feed           FF        \\f
  120.                   carriage return     CR        \\r
  121.                   horizontal tab      HT        \\t
  122.                   backslash           \\         \\\\
  123.  
  124. EXAMPLES
  125.      On a UNIX system, the following command would extract the manual
  126.      pages from all C files in the current UNIX directory, paginate
  127.      them to 52 lines, and place the results in a file called manual.
  128.  
  129.           $ cat *.c | manx -c 52 > manual
  130.  
  131.      Catenating files is much for difficult in DOS.  For that system,
  132.      the following sequence of commands is required.
  133.  
  134.           > copy file.c/a+file2.c+file3.c+file4.c tmp
  135.           > type tmp | manx -c 52 > manual
  136.           > del tmp
  137.  
  138.      It is strongly recommended that a DOS version of cat be obtained
  139.      for use with manx.
  140.  
  141. NOTES
  142.      manx is particularly convenient when used in conjunction with a
  143.      make utility.  Below are the relevant parts of the UNIX makefile
  144.      of an actual C library for which manx is used to extract the
  145.      reference manual.
  146.  
  147.           LIB   = blkio
  148.           MAN   = $(LIB).man
  149.  
  150.           MANS  = blkio.h                                \\
  151.                   bclose.c bexit.c  bflpop.c  bflpush.c  \\
  152.                   bflush.c bgetb.c  bgetbf.c  bgeth.c    \\
  153.                   bgethf.c bopen.c  bputb.c   bputbf.c   \\
  154.                   bputh.c  bputhf.c bsetbuf.c bsetvbuf.c \\
  155.                   bsync.c  lockb.c
  156.  
  157.           man:    $(MAN)
  158.  
  159.           $(MAN): $(MANS)
  160.                   cat $(MANS) | manx > $@
  161.  
  162.      The reference manual for this library is generated with the
  163.      command
  164.  
  165.           make man
  166.  
  167. ------------------------------------------------------------------------------*/
  168. #ifdef AC_PROTO
  169. int main(int argc, char *argv[])
  170. #else
  171. int main(argc, argv)
  172. int argc;
  173. char *argv[];
  174. #endif
  175. {
  176.     char *    endptr        = NULL;        /* pointer for strtol fct */
  177.     int    i        = 0;        /* loop index */
  178.     int    lang        = LANG;        /* default language */
  179.     long    line        = 0;        /* line number */
  180.     long    page        = 0;        /* page number */
  181.     long    pagelen        = PAGELEN;    /* default page length */
  182.     char *    progname    = PROGNAME;    /* program name */
  183.     char    s[LINELEN_MAX + 1];        /* input line */
  184.  
  185.     /* process command line options and arguments */
  186.     if (argc > 0) {                /* program name */
  187.         progname = *argv;
  188.         --argc;
  189.         ++argv;
  190.     }
  191.     if (argc > 0 && *argv[0] == '-') {    /* language option */
  192.         lang = 0;
  193.         for (i = 0; i < sizeof(langs) / sizeof(*langs); ++i) {
  194.             if (strcmp(*argv + 1, langs[i].option) == 0) {
  195.                 lang = i + 1;
  196.                 break;
  197.             }
  198.         }
  199.         if (lang == 0) {
  200.             fprintf(stderr, "%s: illegal option -- %s\n", progname, *argv + 1);
  201.             fprintf(stderr, USAGE, progname);
  202.             exit(EXIT_FAILURE);
  203.         }
  204.         --argc;
  205.         ++argv;
  206.     }
  207.     if (argc > 0) {                /* page length argument */
  208.         errno = 0;
  209.         pagelen = strtol(*argv, &endptr, 10);
  210.         if (errno == ERANGE) {
  211.             fprintf(stderr, "%s: page length %s too large", progname, *argv);
  212.             fprintf(stderr, USAGE, progname);
  213.             exit(EXIT_FAILURE);
  214.         }
  215.         if (endptr != NULL) {
  216.             if (endptr[0] != '\0') {
  217.                 fprintf(stderr, USAGE, progname);
  218.                 exit(EXIT_FAILURE);
  219.             }
  220.         }
  221.         if (pagelen < 0) {
  222.             fprintf(stderr, USAGE, progname);
  223.             exit(EXIT_FAILURE);
  224.         }
  225.         --argc;
  226.         ++argv;
  227.     }
  228.     if (argc != 0) {
  229.         fprintf(stderr, USAGE, progname);
  230.         exit(EXIT_FAILURE);
  231.     }
  232.  
  233.     /* main loop */
  234.     for (;;) {
  235.         /* read next line of input */
  236.         if (fgets(s, (int)sizeof(s), stdin) == NULL) {
  237.             if (ferror(stdin) != 0) {
  238.                 fprintf(stderr, "%s: *** Error reading input.  Exiting.\n", progname);
  239.                 exit(EXIT_FAILURE);
  240.             }
  241.             break;
  242.         }
  243.         /* check for manual entry marker at beginning of line */
  244.         if (strncmp(s, langs[lang - 1].begin, strlen(langs[lang - 1].begin)) != 0) {
  245.             continue;
  246.         }
  247.         if (langs[lang - 1].flags & BLOCKCMT) {
  248.             if (strstr(s, langs[lang - 1].end) != NULL) {
  249.                 continue;
  250.             }
  251.         }
  252.         /* inner loop */
  253.         line = 0;
  254.         page = 1;
  255.         for (;;) {
  256.             ++line;
  257.             /* read next line of manual entry */
  258.             if (fgets(s, (int)sizeof(s), stdin) == NULL) {
  259.                 if (ferror(stdin) != 0) {
  260.                     fprintf(stderr, "%s: *** Error reading standard input.  Exiting.\n", progname);
  261.                     exit(EXIT_FAILURE);
  262.                 }
  263.                 break;
  264.             }
  265.             /* check for end of entry marker */
  266.             if (langs[lang - 1].flags & LINECMT) {
  267.                 if (strncmp(s, langs[lang - 1].end, strlen(langs[lang - 1].end)) == 0) {
  268.                     break;
  269.                 }
  270.                 if (strncmp(s, langs[lang - 1].comment, strlen(langs[lang - 1].comment)) != 0) {
  271.                     break;
  272.                 }
  273.             } else {
  274.                 if (strstr(s, langs[lang - 1].end) != NULL) {
  275.                     break;
  276.                 }
  277.             }
  278.             if (s[strlen(s) - 1] != '\n') {
  279.                 fprintf(stderr, "%s: *** Warning.  Maximum line length of %d exceeded.  Page %ld, line %ld.\n", progname, (int)(sizeof(s) - 2), page, line);
  280.                 s[strlen(s) - 1] = '\n';
  281.             }
  282.             if (langs[lang - 1].flags & LINECMT) {
  283.                 if (manputs(s + strlen(langs[lang - 1].comment) , stdout, &page, &line) == -1) {
  284.                     fprintf(stderr, "%s: *** Error writing line %ld, of page %ld.  Exiting\n", progname, line, page);
  285.                     exit(EXIT_FAILURE);
  286.                 }
  287.             } else {
  288.                 if (manputs(s, stdout, &page, &line) == -1) {
  289.                     fprintf(stderr, "%s: *** Error writing line %ld, of page %ld.  Exiting\n", progname, line, page);
  290.                     exit(EXIT_FAILURE);
  291.                 }
  292.             }
  293.             if (line >= pagelen && pagelen != 0) {
  294.                 if (fputs(PAGINATOR, stdout) == EOF) {
  295.                     fprintf(stderr, "%s: *** Error writing paginator to standard output.  Exiting.\n", progname);
  296.                     exit(EXIT_FAILURE);
  297.                 }
  298.                 line = 0;
  299.                 ++page;
  300.             }
  301.         }
  302.         /* write last paginator */
  303.         if (line != 1 && pagelen != 0) {
  304.             if (fputs(PAGINATOR, stdout) == EOF) {
  305.                 fprintf(stderr, "%s: *** Error writing paginator to standard output.  Exiting.\n", progname);
  306.                 exit(EXIT_FAILURE);
  307.             }
  308.             ++page;
  309.         }
  310.         /* check if end of file */
  311.         if (feof(stdin) != 0) {
  312.             break;
  313.         }
  314.     }
  315.  
  316.     exit(EXIT_SUCCESS);
  317. }
  318.  
  319. /*------------------------------------------------------------------------------
  320. NAME
  321.      manputs - manual entry put
  322.  
  323. SYNOPSIS
  324.      static int manputs(cs, fp, pagep, linep)
  325.      const char *cs;
  326.      FILE *fp;
  327.      long *pagep;
  328.      long *linep;
  329.  
  330. DESCRIPTION
  331.      The manputs function writes the null-terminated string pointed to
  332.      by cs to the named output stream.  Any manx escape sequence found
  333.      in the string is converted to the character it represents before
  334.      being output.
  335.  
  336. DIAGNOSTICS
  337.      Upon successful completion, a value of 0 is returned.  Otherwise,
  338.      a value of -1 is returned.
  339.  
  340. ------------------------------------------------------------------------------*/
  341. #ifdef AC_PROTO
  342. static int manputs(const char *cs, FILE *fp, long *pagep, long *linep)
  343. #else
  344. static int manputs(cs, fp, pagep, linep)
  345. const char *cs;
  346. FILE *fp;
  347. long *pagep;
  348. long *linep;
  349. #endif
  350. {
  351.     char    t[LINELEN_MAX + 1];    /* target string */
  352.     int    i    = 0;        /* index into target string */
  353.     char    c    = '\0';
  354.  
  355.     /* convert string to output format */
  356.     for (i = 0; *cs != '\0'; ++i) {
  357.         if (i > sizeof(t)) {
  358.             return -1;
  359.         }
  360.         c = *cs++;
  361.         /* check for escape sequence */
  362.         if (c == BACKSLASH && *cs != '\0') {
  363.             c = *cs++;
  364.             switch (c) {
  365. #ifdef AC_ESCAPE
  366.             case 'a':    /* audible alert */
  367.                 c = '\a';
  368.                 break;
  369. #endif
  370.             case 'b':    /* backspace */
  371.                 c = '\b';
  372.                 break;
  373.             case 'f':    /* form feed */
  374.                 c = '\f';
  375.                 *linep = 0;
  376.                 ++*pagep;
  377.                 break;
  378.             case 'r':    /* carriage return */
  379.                 c = '\r';
  380.                 break;
  381.             case 't':    /* horizontal tab */
  382.                 c = '\t';
  383.                 break;
  384.             case '\\':    /* backslash */
  385.                 c = '\\';
  386.                 break;
  387.             default:    /* ignore backslash */
  388.                 break;
  389.             }
  390.         }
  391.         t[i] = c;
  392.     }
  393.     t[i] = '\0';
  394.  
  395.     /* write converted string to fp */
  396.     if (fputs(t, fp) == EOF) {
  397.         return -1;
  398.     }
  399.  
  400.     return 0;
  401. }
  402.  
  403. #ifndef AC_STRING
  404. #ifdef AC_PROTO
  405. static char *strstr(const char *cs, const char *ct)
  406. #else
  407. static char *strstr(cs, ct)
  408. const char *cs;
  409. const char *ct;
  410. #endif
  411. {
  412.     int ctlen = 0;
  413.  
  414.     if (cs == NULL || ct == NULL) {
  415.         return NULL;
  416.     }
  417.  
  418.     ctlen = strlen(ct);
  419.     while (*cs != '\0') {
  420.         if (strncmp(cs, ct, ctlen) == 0) {
  421.             return cs;
  422.         }
  423.         ++cs;
  424.     }
  425.  
  426.     return NULL;
  427. }
  428. #endif
  429.